Ink

What is Ink?

In a few words, it’s an open-source scripting language for interactive narratives. It can be used to develop games which is the major focus of this documentation section. More info can be found on the official website.

Before You Start

While reading the official documentation, you might get overwhelmed by Inkle’s unique terms and concepts. Despite being called Ink, it is less about text fluid and more closely related to its creator’s namesake i.e. Inkle. An inkle is a narrow linen tape often used to make shoelaces. Hopefully knowing this makes lingo like knots and threads a little less confusing.

Articles

Lingo

➥Operators

Operator Purpose Example Notes
// Single line comment // Explaining why not describing what Content after // is ignored by the Ink compiler for just that line.
/* */ Multiple line comment /* Not much
is going on here
indeed */
Content between /* and */ is ignored by the Ink compiler.
# Tagging I didn’t do it. #VO_ID_123 Multiple tags per line are allowed, meant for metadata purposes.
* Choice/Option The phone rings.
* Answer
* Ignore
Input mechanism for making decisions.
Once used, it is consumed and never offered again.
+ Sticky Choice/Option The phone rings again.
+ Answer
+ Ignore
A choice that never gets consumed.
It “sticks” around.
[] Text Inline Skip/Break
(for Choices only)
* Jump[?! It’s risky tho…]ing off the cliff was a bad idea.

// Choice: Jump?! It’s risky tho…
// Response: Jumping off the cliff was a bad idea.
Text presented between the square brackets is shown in the choice text but not in its response.
Text after the square brackets is not shown in the choice and only in the response.
This technique is sometimes referred to as Weave-Style.
<> Prevent line breaks I didn’t know <>
what to do!
Called “glue,” it sticks lines together.
Angle brackets must be next to each other, no spaces in between!
Can be used at the end of the first line or beginning of the second.
{} Print variables or expressions VAR dog = “Odie”
VAR cat = “Garfield”

{dog + “ and “ + cat} // Prints: Odie and Garfield
{ 1 > 100 } // Prints: false
Useful for exposing variable values to the reader.
Can also be used for debugging purposes.
Cannot print text content unless you wrap it as a string.
{ | } Variable Text { First Time! | Welcome back! }

Good {& Morning | Afternoon | Evening } to you.

{! Try the fish. | Now, try the stew. | Last one, try the pie! }

Seeing you makes us {~ happy| glad| joyful}!
Called “alternatives,” | separators split text between braces into chunks and shows them:
* Sequences (no prefix) - in order and holds the last one
* Cycles (&) - in order and loops back to the first
* Once-Only (!) - in order and holds the last one as blank
* Shuffle (~) - randomly

Can be nested and used in choices. See docs.
{ : } Inline Condition VAR stat = 9001
{ stat > 9000 : It’s over 9000!! }
It’s a { stat <= 177 : | mis}match.
Evaluates an expression and outputs the following text if it’s true.
If a | separator is used to split the text, only the second chunk is used if false.
* { } Conditional Choice + { HP > 0 } Fight
+ { HP > 10 } { item_count > 0} Use Item
* { RANDOM(1,12) <= 6 } Flee
Activates or deactivates a choice (sticky or not) based on a conditional check.
Multiple conditions can be used, and their expressions can also utilize logical operators
== Section of Text Content == section1
-> DONE

=== section2 ===
-> DONE
Called “knots,” these mark sections of text and give them a label for redirection purposes.
Sections need to flow into other sections or terminate properly with -> DONE or -> END
= Sub-section of Text Content === section1
= subsection1
content
Called “stitches,” these can break up knots to manage huge amounts of text.
Stitches have their own labels and other knots can redirect to them.
-> Go to a specific section === section1
Section 1
-> section2
Called “diverts,” these change the flow of the story by redirecting it.
<- Combine multiple sections into one <- section1
<- section2
=== section1
Section 1
=== section2
Section 2
Called “threads,” these collect content into a single chunk with collected options at the bottom.
It’s a powerful way of combining content and choices.
- Capture story flow * Decide Left
* Decide Right

- Pointless. You can only go forward!
Called “gathers,” these redirect the story to itself.
It’s a type of fallback mechanism often used to create chokepoints for choices that do not divert.
( ) Labels gathers and choices * (picked_left) Decide Left
* Decide Right

- (feedback) You were { picked_left : correct!| wrong…}

+ [Can you repeat that?] -> feedback
* [I’m done.] Goodbye. -> DONE
Allows testing and diverting on gathers and options.
If diverted to a choice, it is immediately chosen.
~ Denotes an expression VAR found = false
I found the ruby!
~ found = true
Sets a line as code to be evaluated instead of text content
+ - * / % Math operators   You can use mod instead of %
== != >= <= < > Comparison operators    
&& || AND/OR Logic operators   You can use and instead of &&.
You can use or instead of ||.
! NOT operator VAR read = true
VAR status = true
~ status = !read
{ status } // false
{ !status } // status (once-only)
{ not status } // true
Negates an expression.
You can use not instead of !, sometimes necessary when used to print with {}.
? Has check VAR status = “Diplomatic Immunity”
{ status ? “Immunity” } // outputs true
Checks if a list variable has a specific flag set.
Checks if a string contains another string (substring).
You can use has instead of ?.
!? “Has not” check   Negation of Has check.
You can use hasnt instead of !?.
^ Intersection check LIST parts = thumb, belly, tail
VAR dog = (belly, tail)
VAR human = (thumb, belly)

{ dog ^ human } // outputs belly
Checks if two list variables have overlapping values.
Returns a list variable.

➥Keywords

Keyword Purpose Example Notes
CONST Defines a global constant CONST PI = 3.1415  
VAR Defines a global variable VAR x = “spot” Always hoisted and initialized once.
Can initialize to a constant but not to other variables nor expressions.
temp Defines a temporary variable ~ temp doublePI = PI * 2 Only exists in the knot/stitch it was defined in.
Needs ~ to be evaluated.
LIST Defines an Ink List LIST weekdays = Mon, Tues, Wed, Thurs, Fri Lists are variables that are Boolean sets as well as enums.
Read the official docs for more info.
function Defines an Ink function VAR item_count = 10

You were robbed.
{get_robbed()} // function call
You have {item_count} items. // outputs 0

== function get_robbed()
~ item_count = 0
Functions are knots that can call other functions and return values.
They do not support diverts, choices and stitches. Labelled gathers are supported.

Since they are knots, == needs to be prefixed.

Functions are called with () within ~ or {}, the latter prints the return value, if any.
return Function return { square(10) } // outputs 100

=== function square(x)
~ return x * x
Stops function evaluation and returns a value.
Needs ~ to be processed.
else Condition block run if all fails { RANDOM(1,6) > 3 :
You win.
- else:
You lose.
}
Acts like else in if-else statement.
Acts like default in switch-case statement.
true, false Values of boolean variables   Reserved keywords but only in lowercase. So “True” is okay for a knot-name.
INCLUDE Combines an Ink file with the current one. INCLUDE test.ink Knot and global variable names must be unique or duplicate errors will be reported.
EXTERNAL Defines a game engine function EXTERNAL GetTime() It’s a good idea to implement a fallback function in Ink so that lines that call external functions can run correctly outside of the game engine.